package com.atguigu.tingshu.search.service.impl;

import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch._types.SortOrder;
import co.elastic.clients.elasticsearch._types.query_dsl.BoolQuery;
import co.elastic.clients.elasticsearch._types.query_dsl.NestedQuery;
import co.elastic.clients.elasticsearch.core.SearchRequest;
import co.elastic.clients.elasticsearch.core.SearchResponse;
import co.elastic.clients.elasticsearch.core.search.Hit;
import co.elastic.clients.elasticsearch.core.search.HitsMetadata;
import co.elastic.clients.elasticsearch.indices.Queries;
import com.atguigu.tingshu.album.AlbumFeignClient;
import com.atguigu.tingshu.album.CategoryFeignClient;
import com.atguigu.tingshu.common.execption.GuiguException;
import com.atguigu.tingshu.common.result.Result;
import com.atguigu.tingshu.common.result.ResultCodeEnum;
import com.atguigu.tingshu.model.album.AlbumAttributeValue;
import com.atguigu.tingshu.model.album.AlbumInfo;
import com.atguigu.tingshu.model.album.BaseCategoryView;
import com.atguigu.tingshu.model.search.AlbumInfoIndex;
import com.atguigu.tingshu.model.search.AttributeValueIndex;
import com.atguigu.tingshu.query.search.AlbumIndexQuery;
import com.atguigu.tingshu.search.repository.AlbumIndexRepository;
import com.atguigu.tingshu.search.service.SearchService;
import com.atguigu.tingshu.user.client.UserFeignClient;
import com.atguigu.tingshu.vo.search.AlbumInfoIndexVo;
import com.atguigu.tingshu.vo.search.AlbumSearchResponseVo;
import com.atguigu.tingshu.vo.user.UserInfoVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.print.attribute.Attribute;
import java.io.IOException;
import java.util.List;
import java.util.Random;
import java.util.stream.Collectors;


@Slf4j
@Service
@SuppressWarnings({"all"})
public class SearchServiceImpl implements SearchService {

    @Autowired
    private AlbumFeignClient albumFeignClient;

    @Autowired
    private CategoryFeignClient categoryFeignClient;

    @Autowired
    private UserFeignClient userFeignClient;

    @Autowired
    private AlbumIndexRepository albumIndexRepository;

    @Autowired
    private ElasticsearchClient elasticsearchClient;

    /**
     * 专辑上架
     *
     * @param albumId
     */
    @Override
    public void upperAlbum(Long albumId) {
        AlbumInfoIndex albumInfoIndex = new AlbumInfoIndex();
        //远程获取专辑
        Result<AlbumInfo> albumInfoResult = albumFeignClient.getAlbumInfoById(albumId);
        AlbumInfo albumInfo = albumInfoResult.getData();
        if (albumInfo == null) {
            throw new GuiguException(ResultCodeEnum.DATA_ERROR);
        }
        //赋值数据
        BeanUtils.copyProperties(albumInfo, albumInfoIndex);

        //获取分类信息
        Result<BaseCategoryView> categoryViewResult = categoryFeignClient.getCategoryView(albumInfo.getCategory3Id());
        BaseCategoryView categoryView = categoryViewResult.getData();
        if (categoryView == null) {
            throw new GuiguException(ResultCodeEnum.DATA_ERROR);
        }
        //赋值
        albumInfoIndex.setCategory1Id(categoryView.getCategory1Id());
        albumInfoIndex.setCategory2Id(categoryView.getCategory2Id());
        albumInfoIndex.setCategory3Id(categoryView.getCategory3Id());

        //获取属性信息
        Result<List<AlbumAttributeValue>> albumAttributeValueResult = albumFeignClient.findAlbumAttributeValue(albumId);
        List<AlbumAttributeValue> albumAttributeValues = albumAttributeValueResult.getData();
        if (albumAttributeValues == null) {
            throw new GuiguException(ResultCodeEnum.DATA_ERROR);
        }
        List<AttributeValueIndex> attributeValueIndexList = albumAttributeValues.stream().map(albumAttributeValue -> {
            AttributeValueIndex attributeValueIndex = new AttributeValueIndex();
            attributeValueIndex.setAttributeId(albumAttributeValue.getAttributeId());
            attributeValueIndex.setValueId(albumAttributeValue.getValueId());
            return attributeValueIndex;
        }).collect(Collectors.toList());
        albumInfoIndex.setAttributeValueIndexList(attributeValueIndexList);

        //获取用户名称
        Result<UserInfoVo> userInfoVoResult = userFeignClient.getUserInfoVo(albumInfo.getUserId());

        UserInfoVo userInfoVo = userInfoVoResult.getData();
        if (userInfoVo == null) {
            throw new GuiguException(ResultCodeEnum.DATA_ERROR);
        }
        albumInfoIndex.setAnnouncerName(userInfoVo.getNickname());


        //更新统计量与得分，默认随机，方便测试
        int num1 = new Random().nextInt(1000);
        int num2 = new Random().nextInt(100);
        int num3 = new Random().nextInt(50);
        int num4 = new Random().nextInt(300);
        albumInfoIndex.setPlayStatNum(num1);
        albumInfoIndex.setSubscribeStatNum(num2);
        albumInfoIndex.setBuyStatNum(num3);
        albumInfoIndex.setCommentStatNum(num4);
        double hotScore = num1 * 0.2 + num2 * 0.3 + num3 * 0.4 + num4 * 0.1;
        //  设置热度排名
        albumInfoIndex.setHotScore(hotScore);
        //  保存商品上架信息
        albumIndexRepository.save(albumInfoIndex);
    }

    /**
     * 下架专辑
     *
     * @param albumId
     * @return
     */
    @Override
    public void lowerAlbum(Long albumId) {
        albumIndexRepository.deleteById(albumId);
    }

    /**
     * 专辑搜索列表
     *
     * @param albumIndexQuery
     * @return
     */
    @Override
    public AlbumSearchResponseVo search(AlbumIndexQuery albumIndexQuery) {
        AlbumSearchResponseVo albumSearchResponseVo = null;
        try {
            SearchRequest searchRequest = this.buildQueryDsl(albumIndexQuery);
            SearchResponse<AlbumInfoIndex> searchResponse = elasticsearchClient.search(searchRequest, AlbumInfoIndex.class);
            albumSearchResponseVo = this.parseResultData(searchResponse);

            albumSearchResponseVo.setPageNo(albumIndexQuery.getPageNo()); //当前页面
            albumSearchResponseVo.setPageSize(albumIndexQuery.getPageSize()); //每页显示内容
            albumSearchResponseVo.setTotalPages(albumSearchResponseVo.getTotalPages());

            Long totalPages = (albumIndexQuery.getPageSize() + albumSearchResponseVo.getTotal() - 1) / albumIndexQuery.getPageSize();
            albumSearchResponseVo.setTotal(totalPages);

        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        return albumSearchResponseVo;
    }

    /**
     * 获取结果集
     *
     * @param searchResponse
     * @return
     */
    private AlbumSearchResponseVo parseResultData(SearchResponse<AlbumInfoIndex> searchResponse) {
        //创建对象
        AlbumSearchResponseVo searchResponseVo = new AlbumSearchResponseVo();
        //获取数据
        HitsMetadata<AlbumInfoIndex> hits = searchResponse.hits();
        List<Hit<AlbumInfoIndex>> subHits = hits.hits();
        if (!CollectionUtils.isEmpty(subHits)){
            List<AlbumInfoIndexVo> albumInfoIndexVoList = subHits.stream().map(albumInfoIndexHit -> {
                AlbumInfoIndexVo albumInfoIndexVo = new AlbumInfoIndexVo();
                AlbumInfoIndex albumInfoIndex = albumInfoIndexHit.source();
                BeanUtils.copyProperties(albumInfoIndex, albumInfoIndexVo);
                //判断用户是否根据关键词进行检索
                if (null != albumInfoIndexHit.highlight().get("albumTitle")){
                    //获取高亮数据
                    String albumTitle = albumInfoIndexHit.highlight().get("albumTitle").get(0);
                    albumInfoIndexVo.setAlbumTitle(albumTitle);
                }
                return albumInfoIndexVo;
            }).collect(Collectors.toList());
            //赋值
            searchResponseVo.setList(albumInfoIndexVoList);
        }

        //总记录数
        searchResponseVo.setTotal(hits.total().value());

        //返回数据
        return searchResponseVo;

    }

    /**
     * 获取查询请求对象
     *
     * @param albumIndexQuery
     * @return
     */
    private SearchRequest buildQueryDsl(AlbumIndexQuery albumIndexQuery) {
        String keyword = albumIndexQuery.getKeyword();
        //创建对象
        SearchRequest.Builder requestBuilder = new SearchRequest.Builder();
        BoolQuery.Builder boolQuery = new BoolQuery.Builder();
        //
        if (StringUtils.isEmpty(keyword)) {
            boolQuery.should(f -> f.match(s -> s.field("albumTitle").query(keyword)));
            boolQuery.should(f -> f.match(s -> s.field("albumIntro").query(keyword)));
        }

        //一级分类id
        Long category1Id = albumIndexQuery.getCategory1Id();
        if (category1Id != null) {
            boolQuery.filter(f -> f.term(s -> s.field("category1Id").value(category1Id)));
        }
        //二级分类id
        Long category2Id = albumIndexQuery.getCategory2Id();
        if (category1Id != null) {
            boolQuery.filter(f -> f.term(s -> s.field("category2Id").value(category2Id)));
        }
        //三级分类id
        Long category3Id = albumIndexQuery.getCategory3Id();
        if (category2Id != null) {
            boolQuery.filter(f -> f.term(s -> s.field("category3Id").value(category3Id)));
        }

        //根据属性id检索
        List<String> attributeList = albumIndexQuery.getAttributeList();
        if (!CollectionUtils.isEmpty(attributeList)) {

            for (String attrbute : attributeList) {
                String[] split = attrbute.split(".");
                if (null != split && split.length == 2) {
                    NestedQuery nestedQuery = NestedQuery.of(f -> f.path("attributeValueIndexList")
                            .query(q -> q.bool(
                                    m -> m.must(s ->
                                                    s.match(a -> a.field("attributeValueIndexList.attributeId")
                                                            .query(split[0])
                                                    ))
                                            .must(s ->
                                                    s.match(a -> a.field("attributeValueIndexList.valueId")
                                                            .query(split[1])
                                                    ))
                            ))
                    );
                    boolQuery.filter(f -> f.nested(nestedQuery));
                }
            }
        }

        //排序
        String order = albumIndexQuery.getOrder();
        String orderField = "";
        String sort = "";
        if (!StringUtils.isEmpty(order)) {
            String[] split = order.split(":");
            if (null != split && split.length == 2) {
                switch (split[0]) {
                    case "1":
                        orderField = "hotScore";
                        break;
                    case "2":
                        orderField = "playStatNum";
                        break;
                    case "3":
                        orderField = "createTime";
                        break;
                }
                sort = split[1];
            }
        }
        SortOrder sortOrder = "asc".equals(sort) ? SortOrder.Asc : SortOrder.Desc;
        String finalOrderField = orderField;
        requestBuilder.sort(f->f.field(o->o.field(finalOrderField).order(sortOrder)));

        //分页
        requestBuilder.from((albumIndexQuery.getPageNo() - 1) * albumIndexQuery.getPageSize());
        requestBuilder.size(albumIndexQuery.getPageSize());

        //高亮
        requestBuilder.highlight(h->h.fields("albumTitle",
                f->f.preTags("<font color:red>").postTags("</font>")
                ));

        //Get /albumInfo/_search
        requestBuilder.index("albuminfo").query(f->f.bool(boolQuery.build()));

        //创建对象
        SearchRequest searchRequest = requestBuilder.build();

        System.out.println(searchRequest.toString());

        return searchRequest;
    }
}
